#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import git
import json
import smtplib
import datetime
import traceback
import subprocess

from constants import *
from email.mime.text import MIMEText


class Committer(object):
    def __init__(self, queue, notify):
        LOG.info("[commit] committer thread started.")
        self._queue = queue
        self._notify = notify
        self._mail_addr="smtphz.qiye.163.com"
        self._mail_usr="wei.zhijun@99cloud.net"
        self._mail_pwd="Weizj@334965317"
        self._git_clone(RPM_PACKAGING_URL)

    def _send_mail(self, title, context):
        msg = MIMEText(context, _subtype='plain', _charset='gb2312')
        msg['Subject'] = title
        msg['From'] = self._mail_usr
        msg['To'] = self._mail_usr
        try:
            server = smtplib.SMTP()
            server.connect(self._mail_addr)
            server.login(self._mail_usr, self._mail_pwd)
            server.sendmail(self._mail_usr, self._mail_usr, msg.as_string())
            server.close()
        except Exception, e:
            LOG.error(str(e))
        return

    def _git_clone(self, url):
        start = datetime.datetime.now()
        if os.path.isdir(RPM_PACKAGING_PATH):
            self.repo = git.Repo.init(RPM_PACKAGING_PATH + "/.git")
        else:
            self.repo = git.Repo.clone_from(url, RPM_PACKAGING_PATH, branch="master")
        end = datetime.datetime.now()
        os.system("\cp -fp %s/conf/config %s/.git/" % (MA_SISTER_PATH, RPM_PACKAGING_PATH))
        os.chdir(RPM_PACKAGING_PATH)
        git.Git().pull()
        LOG.info("[commit] rpm-packaging init ok, took %s seconds" % (end - start).seconds)
        return

    def _create_branch(self, project_name):
        os.chdir(RPM_PACKAGING_PATH)
        git.Git().pull()
        assert self.repo.active_branch == self.repo.heads.master
        new_branch = self.repo.create_head(project_name, "origin/master")
        self.repo.head.reference = new_branch
        LOG.warning("[commit] create branch: %s!" % project_name)
        return

    def _delete_branch(self, project_name):
        os.chdir(RPM_PACKAGING_PATH)
        if self.repo.active_branch == self.repo.heads.master:
            return
        self.repo.git.checkout("master")
        assert self.repo.active_branch == self.repo.heads.master
        self.repo.delete_head(project_name, force=True)
        LOG.warning("[commit] delete branch: %s!" % project_name)
        return

    def _get_rpm_patch(self):
        try:
            r = requests.get(RPM_PACKAGING_PATCH_URL, timeout=10, headers={"Connection":"close"})
            with open("%s" % PATCH_FILE, "wb") as code:
                code.write(r.content)
            os.system("sed -i '1d' %s" % PATCH_FILE)
        except:
            raise TimeoutError()

        with open("%s" % PATCH_FILE, "r") as f:
            context = json.load(f)
        if not context:
            return {}

        return context

    def _patch_exist(self, context, project_name):
        for obj in context:
            if cmp(obj.get("branch"), "master"):
                continue
            subject = obj.get("subject")
            if not subject:
                continue

            lname = project_name.lower()
            _str = "%s " % lname
            if _str in subject.lower():
                LOG.warning("[commit] %s has a patch on the way, ignore it!" % project_name)
                return True
        return False

    def _process(self, context, project):
        LOG.info("[commit] %s, checking..." % project)
        if self._patch_exist(context, project.name):
            return

        try:
            self._create_branch(project.name)
        except Exception:
            LOG.error("[commit] failed to create branch %s." % project.name)
            self._delete_branch(project.name)
            self._notify.put(project.depend_id)
            return

        j2_file = J2_PATH % (RPM_PACKAGING_PATH, project.name, project.name + ".spec.j2")
        os.system("sed -i 's/%s/%s/g' %s" % (project.old, project.new, j2_file))

        DESC = "Updated %s to %s" % (project.name, project.new)
        need_send = False
        try:
            os.system("rm -f %s/.git/hooks/commit-msg" % RPM_PACKAGING_PATH)
            os.system("\cp -fp %s/conf/commit-msg %s/.git/hooks/" % (MA_SISTER_PATH, RPM_PACKAGING_PATH))

            self.repo.git.add(j2_file)
            # if project.depend_id:
            #    self.repo.git.commit("-m", DESC, "-m", "Depends-on:" + project.depend_id)
            # else:
            self.repo.git.commit("-m", DESC)

            os.chdir(RPM_PACKAGING_PATH)
            proc = subprocess.Popen(["git review"], stdout=subprocess.PIPE, shell=True)
            (out, err) = proc.communicate()
            LOG.info("[commit] %s" % out)
            need_send = True
        except Exception:
            LOG.error("[commit] git review error: %s" % traceback.format_exc())
            self._notify.put(project.depend_id)
        finally:
            self._delete_branch(project.name)

        if need_send:
            self._send_mail("Git review: %s - %s" % (project.name, DESC), "FYI")

    def process_event(self):
        while True:
            project_set = self._queue.get()
            LOG.info("[commit] receive %s messages." % len(project_set))
            try:
                context = self._get_rpm_patch()
                for project_obj in project_set:
                    self._process(context, project_obj)
                    LOG.info("[search] ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞")
            except TimeoutError:
                LOG.error("[commit] get rpm patch timeout.")
                self._notify.put("destory")
            except:
                LOG.error("[commit] process_event failed. %s" % traceback.format_exc())
                self._notify.put("destory")

